from fastapi import FastAPI, UploadFile, File, Form, HTTPException, Body
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel
import aiofiles
import uuid
from pathlib import Path
import logging
from datetime import datetime
import os
from dotenv import load_dotenv
from typing import Dict, Any, Optional
import json

# 导入改进的实现
from working_whisper import WorkingWhisperASR
from improved_llm import ImprovedKimiClient, MeetingMinutesRoles
from role_based_llm import RoleBasedProcessor

# 加载.env文件
load_dotenv()

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# 创建FastAPI应用
app = FastAPI(title="AI Meeting Minutes API", version="2.0.0")

# CORS中间件
app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:5173", "http://localhost:3000"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# 静态文件服务
app.mount("/uploads", StaticFiles(directory="uploads"), name="uploads")

# 配置
UPLOAD_DIR = Path(os.getenv("UPLOAD_DIR", "uploads"))
MAX_FILE_SIZE = int(os.getenv("MAX_FILE_SIZE", "104857600"))  # 100MB
ALLOWED_EXTENSIONS = set(json.loads(os.getenv("ALLOWED_AUDIO_EXTENSIONS", '["mp3","wav","m4a","ogg","flac","aac"]')))

# 确保上传目录存在
UPLOAD_DIR.mkdir(exist_ok=True)

# 全局变量存储改进的服务实例
whisper_service: Optional[WorkingWhisperASR] = None
kimi_client: Optional[ImprovedKimiClient] = None
meeting_roles: Optional[MeetingMinutesRoles] = None
role_processor: Optional[RoleBasedProcessor] = None

# Pydantic模型
class MeetingCreate(BaseModel):
    title: str
    description: str = ""
    date: str = ""

class MinutesGenerate(BaseModel):
    meeting_id: str
    template: Optional[str] = "标准会议纪要"

# 内存存储
meetings_storage = {}
transcripts_storage = {}
minutes_storage = {}

# 初始化服务
def initialize_services():
    """初始化所有服务"""
    global whisper_service, kimi_client, meeting_roles, role_processor

    try:
        logger.info("🚀 正在初始化AI服务...")

        # 初始化Whisper服务
        device = os.getenv("WHISPER_DEVICE", "cuda:9")
        logger.info(f"🎤 初始化Whisper服务，设备: {device}")
        whisper_service = WorkingWhisperASR(device=device)

        # 初始化Kimi客户端
        logger.info("🤖 初始化Kimi客户端...")
        kimi_client = ImprovedKimiClient()

        # 初始化会议角色系统
        logger.info("📋 初始化会议角色系统...")
        meeting_roles = MeetingMinutesRoles(kimi_client)

        # 初始化基于角色的处理器
        api_key = os.getenv("KIMI_API_KEY")
        if api_key:
            logger.info("🎭 初始化基于角色的处理器...")
            role_processor = RoleBasedProcessor(api_key=api_key)
        else:
            logger.warning("⚠️ 未配置KIMI_API_KEY，基于角色的处理器将不可用")

        logger.info("✅ 所有服务初始化完成")

    except Exception as e:
        logger.error(f"❌ 服务初始化失败: {e}")
        raise

@app.on_event("startup")
async def startup_event():
    """应用启动事件"""
    logger.info("🌟 AI会议纪要系统启动中...")
    initialize_services()
    logger.info("🎉 系统启动完成，准备服务请求")

@app.get("/")
async def root():
    return {"message": "AI Meeting Minutes API v2.0.0", "status": "running"}

@app.get("/api/v1/health")
async def health_check():
    """健康检查端点"""
    status = {
        "status": "healthy",
        "timestamp": datetime.now().isoformat(),
        "services": {
            "whisper": whisper_service is not None,
            "kimi": kimi_client is not None,
            "roles": meeting_roles is not None
        }
    }
    return status

def validate_audio_file(file: UploadFile) -> Path:
    """验证音频文件"""
    # 检查文件扩展名
    filename = file.filename or 'recording.wav'  # 提供默认文件名
    file_extension = filename.split('.')[-1].lower() if '.' in filename else 'wav'

    if file_extension not in ALLOWED_EXTENSIONS:
        raise HTTPException(
            status_code=400,
            detail=f"不支持的文件格式。支持的格式: {', '.join(ALLOWED_EXTENSIONS)}"
        )

    # 检查文件大小
    if file.size and file.size > MAX_FILE_SIZE:
        raise HTTPException(
            status_code=400,
            detail=f"文件过大。最大允许大小: {MAX_FILE_SIZE // (1024*1024)}MB"
        )

    # 生成唯一文件名
    file_id = str(uuid.uuid4())
    file_path = UPLOAD_DIR / f"{file_id}.{file_extension}"

    return file_path

@app.post("/api/v1/meetings")
async def create_meeting(meeting_data: MeetingCreate):
    """创建新会议"""
    meeting_id = str(uuid.uuid4())

    meeting_record = {
        "id": meeting_id,
        "title": meeting_data.title,
        "description": meeting_data.description,
        "date": meeting_data.date or datetime.now().strftime("%Y-%m-%d"),
        "created_at": datetime.now().isoformat(),
        "status": "created"
    }

    meetings_storage[meeting_id] = meeting_record
    logger.info(f"📝 创建会议: {meeting_data.title} (ID: {meeting_id})")

    return {"meeting_id": meeting_id, "meeting": meeting_record}

@app.post("/api/v1/audio/transcribe")
async def transcribe_audio_file(
    file: UploadFile = File(...),
    meeting_id: Optional[str] = Form(None)
):
    """转录音频文件"""
    if not whisper_service:
        raise HTTPException(status_code=503, detail="Whisper服务未初始化")

    # 验证会议（如果提供了meeting_id）
    if meeting_id and meeting_id not in meetings_storage:
        raise HTTPException(status_code=404, detail="会议不存在")

    # 如果没有提供meeting_id，创建一个新的
    if not meeting_id:
        meeting_id = str(uuid.uuid4())
        meeting_record = {
            "id": meeting_id,
            "title": "录音转录",
            "description": "通过录音转录创建的会议",
            "date": datetime.now().isoformat(),
            "status": "processing",
            "created_at": datetime.now().isoformat(),
            "updated_at": datetime.now().isoformat()
        }
        meetings_storage[meeting_id] = meeting_record
        logger.info(f"🆕 自动创建会议: {meeting_id}")

    # 验证音频文件
    file_path = validate_audio_file(file)

    try:
        # 保存文件
        async with aiofiles.open(file_path, 'wb') as f:
            content = await file.read()
            await f.write(content)

        logger.info(f"📁 文件已保存: {file_path}")

        # 使用OpenAI Whisper库进行转录
        logger.info("🎵 开始转录音频...")
        result = whisper_service.transcribe(str(file_path))

        # 提取转录文本
        transcription_text = whisper_service.get_text_from_result(result)

        # 提取词级时间戳
        word_timestamps = whisper_service.get_word_timestamps(result)

        # 准备转录数据
        transcription_data = {
            "meeting_id": meeting_id,
            "text": transcription_text,
            "confidence": 0.95,  # Whisper large-v3 通常有很高的置信度
            "duration": 0,  # 可以从音频文件元数据获取
            "word_count": len(transcription_text.split()),
            "word_timestamps": word_timestamps,
            "language": "chinese",
            # "model": "whisper-large-v3",
            "model": "whisper-base",
            "created_at": datetime.now().isoformat(),
            "audio_file": str(file_path)
        }

        # 存储转录结果
        transcript_id = str(uuid.uuid4())
        transcripts_storage[transcript_id] = transcription_data

        # 更新会议状态
        meetings_storage[meeting_id]["status"] = "transcribed"
        meetings_storage[meeting_id]["transcript_id"] = transcript_id

        logger.info(f"✅ 转录完成，文本长度: {len(transcription_text)}字符")
        logger.info(f"📊 词级时间戳数量: {len(word_timestamps)}")

        return {
            "transcript_id": transcript_id,
            "transcription": transcription_data
        }

    except Exception as e:
        logger.error(f"❌ 转录失败: {e}")
        # 清理文件
        if file_path.exists():
            file_path.unlink()
        raise HTTPException(status_code=500, detail=f"转录失败: {str(e)}")

@app.post("/api/v1/minutes/generate")
async def generate_meeting_minutes(request_data: dict):  # 临时改为dict接收任意数据
    """生成会议纪要"""
    try:
        # 手动解析数据
        meeting_id = request_data.get("meeting_id")
        template = request_data.get("template", "标准会议纪要")

        logger.info(f"🔍 收到纪要生成请求: meeting_id={meeting_id}, template={template}")

        if not meeting_id:
            raise HTTPException(status_code=400, detail="meeting_id是必需的")

        if not role_processor:
            raise HTTPException(status_code=503, detail="LLM服务未初始化")

        # 获取会议信息
        meeting_data = meetings_storage.get(meeting_id, {})
        if not meeting_data:
            raise HTTPException(status_code=404, detail="会议不存在")

        # 查找该会议的转录内容
        transcript_data = None
        transcript_id = None

        logger.info(f"🔍 查找会议 {meeting_id} 的转录内容...")
        logger.info(f"📊 当前转录存储数量: {len(transcripts_storage)}")

        for tid, tdata in transcripts_storage.items():
            logger.info(f"检查转录 {tid}: meeting_id={tdata.get('meeting_id')}")
            if tdata.get("meeting_id") == meeting_id:
                transcript_data = tdata
                transcript_id = tid
                logger.info(f"✅ 找到转录内容: {tid}")
                break

        if not transcript_data:
            logger.error(f"❌ 未找到会议 {meeting_id} 的转录内容")
            logger.error(f"可用转录: {list(transcripts_storage.keys())}")
            logger.error(f"可用会议: {list(meetings_storage.keys())}")
            raise HTTPException(status_code=404, detail="转录内容不存在，请先上传音频文件")

        final_title = meeting_data.get("title", "会议纪要")

        logger.info(f"🚀 开始生成会议纪要: {final_title}")
        logger.info(f"📝 使用模板: {template}")
        logger.info(f"📄 转录文本长度: {len(transcript_data['text'])}字符")

        # 验证转录文本不为空
        transcript_text = transcript_data["text"]
        if not transcript_text or not transcript_text.strip():
            logger.error("❌ 转录文本为空，无法生成会议纪要")
            raise HTTPException(status_code=400, detail="转录内容为空，无法生成会议纪要")

        logger.info(f"✅ 转录文本内容预览: {transcript_text[:100]}...")

        # 使用基于角色的处理器生成会议纪要（多阶段处理）
        minutes_content = role_processor.process_transcript_to_minutes(
            transcript_text=transcript_text,
            progress_callback=lambda progress: logger.info(f"📊 生成进度: {progress}%")
        )

        # 准备纪要数据
        minutes_data = {
            "meeting_id": meeting_id,
            "transcript_id": transcript_id,
            "title": final_title,
            "content": minutes_content,
            "template": template,
            "generated_at": datetime.now().isoformat(),
            "model": "moonshot-v1-8k",
            "word_count": len(minutes_content)
        }

        # 存储纪要
        minutes_id = str(uuid.uuid4())
        minutes_storage[minutes_id] = minutes_data

        # 更新会议状态
        meetings_storage[meeting_id]["status"] = "completed"
        meetings_storage[meeting_id]["minutes_id"] = minutes_id

        logger.info(f"✅ 会议纪要生成完成，长度: {len(minutes_content)}字符")

        return {
            "minutes_id": minutes_id,
            "minutes": minutes_data
        }

    except Exception as e:
        logger.error(f"❌ 生成会议纪要失败: {e}")
        raise HTTPException(status_code=500, detail=f"生成会议纪要失败: {str(e)}")

@app.get("/api/v1/meetings/{meeting_id}")
async def get_meeting(meeting_id: str):
    """获取会议信息"""
    if meeting_id not in meetings_storage:
        raise HTTPException(status_code=404, detail="会议不存在")

    meeting_data = meetings_storage[meeting_id]

    # 添加关联的转录和纪要信息
    if "transcript_id" in meeting_data:
        transcript_data = transcripts_storage.get(meeting_data["transcript_id"])
        if transcript_data:
            meeting_data["transcription"] = transcript_data

    if "minutes_id" in meeting_data:
        minutes_data = minutes_storage.get(meeting_data["minutes_id"])
        if minutes_data:
            meeting_data["minutes"] = minutes_data

    return {"meeting": meeting_data}

@app.get("/api/v1/transcripts/{transcript_id}")
async def get_transcript(transcript_id: str):
    """获取转录内容"""
    if transcript_id not in transcripts_storage:
        raise HTTPException(status_code=404, detail="转录内容不存在")

    return {"transcription": transcripts_storage[transcript_id]}

@app.get("/api/v1/minutes/{minutes_id}")
async def get_minutes(minutes_id: str):
    """获取会议纪要"""
    if minutes_id not in minutes_storage:
        raise HTTPException(status_code=404, detail="会议纪要不存在的")

    return {"minutes": minutes_storage[minutes_id]}

@app.get("/api/v1/meetings")
async def list_meetings():
    """列出所有会议"""
    meetings = list(meetings_storage.values())
    meetings.sort(key=lambda x: x.get("created_at", ""), reverse=True)
    return {"meetings": meetings}

@app.delete("/api/v1/meetings/{meeting_id}")
async def delete_meeting(meeting_id: str):
    """删除会议"""
    if meeting_id not in meetings_storage:
        raise HTTPException(status_code=404, detail="会议不存在")

    meeting_data = meetings_storage[meeting_id]

    # 删除关联的转录和纪要
    if "transcript_id" in meeting_data:
        transcript_id = meeting_data["transcript_id"]
        if transcript_id in transcripts_storage:
            # 删除音频文件
            audio_file = transcripts_storage[transcript_id].get("audio_file")
            if audio_file and Path(audio_file).exists():
                Path(audio_file).unlink()
            del transcripts_storage[transcript_id]

    if "minutes_id" in meeting_data:
        minutes_id = meeting_data["minutes_id"]
        if minutes_id in minutes_storage:
            del minutes_storage[minutes_id]

    # 删除会议
    del meetings_storage[meeting_id]

    logger.info(f"🗑️ 已删除会议: {meeting_id}")
    return {"message": "会议已删除"}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(
        "improved_main:app",
        host="0.0.0.0",
        port=8000,
        reload=True,
        log_level="info"
    )